<?php 
use function \Hprose\Future\co; 
 
class Actor extends \lib\BaseActor
{ 
    public function __construct()
    {
        parent::__construct();
        $this->coid = Booru::$client_addr.'#'.$this->coid;
    }

    public function __destruct(){
        Booru::serverCase(['onexit',$this->coid]);
        parent::__destruct();
    }

    ///////////////// static 异步函数 ///////////////////

    public static function spawn_opt($fn,$args=[],$opt=[/*link,addr?,class*/]){ 
        $opt += [ 'addr'=> Booru::$client_addr ];
        switch($opt['addr']){
            case Booru::$client_addr:
                return parent::spawn_opt($fn,$args,$opt);
            case 'worker':  //短运行（进程池创建 默认随机计数节点
                if(empty($opt['addr']) && count(Booru::$client_workers)){
                    $table = Booru::$client_workers;  
                    $opt['addr'] = $table[array_rand($table)];   
                }   
                return parent::spawn_opt($fn,$args,$opt);
            case 'service'://长运行（单独进程创建
                unset($opt['addr']);
                $defer = Booru::channel($addr,$tick); 
                $fn = $fn->bindTo(null,null);
                $fn = serialize(new \Opis\Closure\SerializableClosure($fn));
                \Proc::fork(function () use ($fn,$args,$opt,$addr,$tick) {
                    Booru::connectServer('service');
                    $coid = yield Actor::spawn_opt($fn,$args,$opt);
                    Booru::clientCase($addr,['resolve',$tick,$coid]);
                });
                return $defer;
            default:  //指定节点
                preg_match('/([\w\.]+:\d+)/',$opt['addr'],$arr);
                if(empty($arr)){
                    throw new \Exception("Error Processing Request", 1);
                } 
                if($fn instanceof \Closure){   
                    $fn = $fn->bindTo(null,null);
                    $fn = (serialize(new \Opis\Closure\SerializableClosure($fn)) );
                }  
                return Booru::clientCall($arr[1],['spawn_opt',$fn,$args,$opt]);
        } 
    }
    public static function spawn($fn,$args=[],$opt=[])
    {
        return static::spawn_opt($fn,$args,$opt+=['addr'=>'worker']);
    } 
    ///////////////// static 同步函数 ///////////////////

    public static function send($coid, $data)
    {
        // if (isset(self::$local_actors[$coid])) {
        //     parent::send($coid, $data);
        // } else { 
        preg_match('/([\d\.]+:\d+)#(\w+)/',$coid,$arr);
        if(empty($arr)){
            throw new \Exception("Error Processing Request", 1);
        }
        Booru::clientCase($arr[1],['send',$coid,$data]);
        //}
    }
    public static function exit($coid,$reason){  
        // if(empty($coid) || isset(self::$local_actors[$coid])){
        //     //Booru::serverCase(['onexit',$coid]);
        //     parent::exit($coid,$reason);
        // }else{
        preg_match('/([\d\.]+:\d+)#(\w+)/',$coid,$arr);
        if(empty($arr)){
            throw new \Exception("Error Processing Request", 1);
        }  
        Booru::clientCase($arr[1],['exit',$coid,$reason]);  
        //}
    } 

 
    //////////////// actor 异步函数 /////////////////////
  
    public function link($coid){
        return co(function()use($coid){ 
            $result = yield $this->monitor($coid); 
            if(self::ref($this->coid,$coid)){
                Booru::serverCase(['onmonitor',$this->coid,$coid]); 
            } 
            //     return 'ok';
            // }else{
            //     return 'err';
            // }
            return $result;
        }); 
    }    
    public function unlink($coid){
        return co(function()use($coid){ 
            $result = yield $this->demonitor($coid);
            Booru::serverCase(['ondemonitor',$this->coid,$coid]);
            self::out($this->coid,$coid); 
            return $result;
        });   
    }


    public function monitor($coid){  
        // if( Actor::ref($coid,$this->coid) ) {
        //     Booru::serverCase(['onmonitor',$coid,$this->coid]); 
        // } else {
            preg_match('/([\d\.]+:\d+)#(\w+)/',$coid,$arr); 
            if(empty($arr)){ 
                //return 'eformat';
                throw new \Exception("Error Processing Request", 1);
            } 
            return Booru::clientCall($arr[1],['monitor',$coid,$this->coid]); 
        //} 
    }
    public function demonitor($coid){  
        // if( Actor::out($coid,$this->coid) ) {
        //     Booru::serverCase(['ondemonitor',$coid,$this->coid]); 
        // } else {
            preg_match('/([\d\.]+:\d+)#(\w+)/',$coid,$arr); 
            if(empty($arr)){
                //return 'eformat';
                throw new \Exception("Error Processing Request", 1);
            } 
            return Booru::clientCall($arr[1],['demonitor',$coid,$this->coid]); 
        //} 
    }

}
